package com.castle.fortress.admin.oa.rest;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.castle.fortress.admin.core.constants.GlobalConstants;
import com.castle.fortress.admin.oa.dto.AttendanceSettingDto;
import com.castle.fortress.admin.oa.entity.DateHolidayEntity;
import com.castle.fortress.admin.oa.entity.HolidayTypeEntity;
import com.castle.fortress.admin.oa.entity.UserHolidaySettingEntity;
import com.castle.fortress.admin.oa.dto.UserHolidaySettingDto;
import com.castle.fortress.admin.oa.enums.AttendanceTypeEnum;
import com.castle.fortress.admin.oa.enums.HolidayCalculateEnum;
import com.castle.fortress.admin.oa.service.AttendanceSettingService;
import com.castle.fortress.admin.oa.service.DateHolidayService;
import com.castle.fortress.admin.oa.service.HolidayTypeService;
import com.castle.fortress.admin.system.entity.SysUser;
import com.castle.fortress.admin.oa.service.UserHolidaySettingService;
import com.castle.fortress.common.utils.ConvertUtil;
import com.castle.fortress.admin.utils.WebUtil;
import com.castle.fortress.common.entity.RespBody;
import com.castle.fortress.common.exception.BizException;
import com.castle.fortress.common.respcode.GlobalRespCode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.logging.log4j.util.Strings;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用户假期余额 api 控制器
 *
 * @author whc
 * @since 2022-11-03
 */
@Api(tags = "用户假期余额api管理控制器")
@RestController
@RequestMapping("/api/oa/userHolidaySetting")
public class ApiUserHolidaySettingController {
    @Autowired
    private UserHolidaySettingService userHolidaySettingService;

    @Autowired
    private AttendanceSettingService attendanceSettingService;


    @Autowired
    private HolidayTypeService holidayTypeService;

    @Autowired
    private DateHolidayService dateHolidayService;

    /**
     * 用户假期余额的分页展示
     *
     * @param userHolidaySettingDto 用户假期余额实体类
     * @param currentPage           当前页
     * @param size                  每页记录数
     * @return
     */
    @ApiOperation("用户假期余额分页展示")
    @GetMapping("/page")
    public RespBody<IPage<UserHolidaySettingDto>> pageUserHolidaySetting(UserHolidaySettingDto userHolidaySettingDto, @RequestParam(required = false) Integer currentPage, @RequestParam(required = false) Integer size) {
        Integer pageIndex = currentPage == null ? GlobalConstants.DEFAULT_PAGE_INDEX : currentPage;
        Integer pageSize = size == null ? GlobalConstants.DEFAULT_PAGE_SIZE : size;
        Page<UserHolidaySettingDto> page = new Page(pageIndex, pageSize);

        IPage<UserHolidaySettingDto> pages = userHolidaySettingService.pageUserHolidaySetting(page, userHolidaySettingDto);
        return RespBody.data(pages);
    }

    /**
     * 用户假期余额保存
     *
     * @param userHolidaySettingDto 用户假期余额实体类
     * @return
     */
    @ApiOperation("用户假期余额保存")
    @PostMapping("/save")
    public RespBody<String> saveUserHolidaySetting(@RequestBody UserHolidaySettingDto userHolidaySettingDto) {
        if (userHolidaySettingDto == null) {
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        UserHolidaySettingEntity userHolidaySettingEntity = ConvertUtil.transformObj(userHolidaySettingDto, UserHolidaySettingEntity.class);
        if (userHolidaySettingService.save(userHolidaySettingEntity)) {
            return RespBody.data("保存成功");
        } else {
            return RespBody.fail(GlobalRespCode.OPERATE_ERROR);
        }
    }

    /**
     * 用户假期余额编辑
     *
     * @param userHolidaySettingDto 用户假期余额实体类
     * @return
     */
    @ApiOperation("用户假期余额编辑")
    @PostMapping("/edit")
    public RespBody<String> updateUserHolidaySetting(@RequestBody UserHolidaySettingDto userHolidaySettingDto) {
        if (userHolidaySettingDto == null || userHolidaySettingDto.getId() == null || userHolidaySettingDto.getId().equals(0L)) {
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        UserHolidaySettingEntity userHolidaySettingEntity = ConvertUtil.transformObj(userHolidaySettingDto, UserHolidaySettingEntity.class);
        if (userHolidaySettingService.updateById(userHolidaySettingEntity)) {
            return RespBody.data("保存成功");
        } else {
            return RespBody.fail(GlobalRespCode.OPERATE_ERROR);
        }
    }

    /**
     * 用户假期余额删除
     *
     * @param ids 用户假期余额id集合
     * @return
     */
    @ApiOperation("用户假期余额删除")
    @PostMapping("/delete")
    public RespBody<String> deleteUserHolidaySetting(@RequestBody List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        if (userHolidaySettingService.removeByIds(ids)) {
            return RespBody.data("保存成功");
        } else {
            return RespBody.fail(GlobalRespCode.OPERATE_ERROR);
        }
    }

    /**
     * 用户假期余额详情
     *
     * @param id 用户假期余额id
     * @return
     */
    @ApiOperation("用户假期余额详情")
    @GetMapping("/info")
    public RespBody<UserHolidaySettingDto> infoUserHolidaySetting(@RequestParam Long id) {
        if (id == null) {
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        UserHolidaySettingEntity userHolidaySettingEntity = userHolidaySettingService.getById(id);
        UserHolidaySettingDto userHolidaySettingDto = ConvertUtil.transformObj(userHolidaySettingEntity, UserHolidaySettingDto.class);
        return RespBody.data(userHolidaySettingDto);
    }
    /**
     * 用于计算请假/出差 游标移动至下一天
     * @param lastTemp
     * @param endDateTime
     * @return
     */
    private boolean nextDay(DateTime lastTemp, DateTime endDateTime) {
        boolean condition = false;
        lastTemp = lastTemp.offset(DateField.DAY_OF_YEAR, 1);
        if (lastTemp.getField(DateField.YEAR) == endDateTime.getField(DateField.YEAR)) {
            //如果为同年 condition需要为 当前日小于等于结束日
            condition = lastTemp.getField(DateField.DAY_OF_YEAR) <= endDateTime.getField(DateField.DAY_OF_YEAR);
        } else {
            //如果不同年 condition需要 为 当前年小于等于结束年
            condition = lastTemp.getField(DateField.YEAR) <= endDateTime.getField(DateField.YEAR);
        }
        return condition;
    }


    /**
     * 计算请假时长
     * @param holidayTypeId
     * @param startTimeStr
     * @param endTimeStr
     * @return
     */
    @ApiOperation("计算请假时长")
    @GetMapping("/calculateHolidayTime")
    public RespBody<HashMap<String, Object>> calculateHolidayTime(Long holidayTypeId, String startTimeStr, String endTimeStr) {

        if (holidayTypeId == null) {
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }

        final HolidayTypeEntity holidayType = holidayTypeService.getById(holidayTypeId);
        if (holidayType == null) {
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        final HashMap<String, Object> response = new HashMap<>();
        if (startTimeStr == null || "".equals(startTimeStr) || "请选择".equals(startTimeStr)) {
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        if (endTimeStr == null || "".equals(endTimeStr) || "请选择".equals(endTimeStr)) {
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        final String[] startTime = startTimeStr.split(" ");
        final String[] endTime = endTimeStr.split(" ");
        final DateTime startDateTime = DateUtil.parse(startTime[0], "yyyy年MM月dd日");
        final DateTime endDateTime = DateUtil.parse(endTime[0], "yyyy年MM月dd日");
        if (startDateTime.getTime() > endDateTime.getTime()) {
            throw new BizException("开始时间不能大于结束时间");
        }
        ArrayList<String> dates = new ArrayList<>();
        if (startDateTime.toDateStr().equals(endDateTime.toDateStr())) {
            if (startTime[1].equals(endTime[1])) {
                dates.add(startDateTime.toDateStr() + "," + startTime[1]);
                response.put("days", "0.5");
                response.put("dates", dates);
                return RespBody.data(response);
            }
            dates.add(startDateTime.toDateStr() + ",全天");
            response.put("days", "1.0");
            response.put("dates", dates);
            return RespBody.data(response);
        }
        DateTime lastTemp = DateUtil.parse(startDateTime.toDateStr());
        double result = 0.0;
        boolean condition = false;

        final SysUser currentUser = WebUtil.currentUser();
        final AttendanceSettingDto attendanceSettingDto = attendanceSettingService.currentUserSetting(currentUser, AttendanceTypeEnum.COMMUTE.getCode());
        do {
            //首先判断法定节假日  如果是则直接跳出
            final Integer calculate = holidayType.getCalculate();
            //判断是否为节假日/工作日
            final QueryWrapper<DateHolidayEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("date", lastTemp.toDateStr());
            queryWrapper.last("limit 1");
            final DateHolidayEntity one = dateHolidayService.getOne(queryWrapper);
            //1为工作日，2为周末，3为节假日
            if (one != null && "3".equals(one.getType().toString())) {
                condition = nextDay(lastTemp, endDateTime);
                continue;
            }
            if (HolidayCalculateEnum.NORMAL.getCode().equals(calculate)) {
                //判断是否为考勤设置的工作日 不是的话 需要执行下一次循环
                final String workDay = attendanceSettingDto.getAttendanceSettingDateEntity().getWorkDay();
                final int field = lastTemp.toJdkDate().getDay();
                if (!workDay.contains(field + "")) {
                    condition = true;
                    continue;
                }
            }
            if (lastTemp.toDateStr().equals(startDateTime.toDateStr())) {
                if ("上午".equals(startTime[1])) {
                    result += 1;
                    dates.add(startDateTime.toDateStr() + ",全天");
                }
                if ("下午".equals(startTime[1])) {
                    result += 0.5;
                    dates.add(startDateTime.toDateStr() + ",下午");
                }
            } else if (lastTemp.toDateStr().equals(endDateTime.toDateStr())) {
                if ("上午".equals(endTime[1])) {
                    result += 0.5;
                    dates.add(endDateTime.toDateStr() + ",上午");
                }
                if ("下午".equals(endTime[1])) {
                    result += 1;
                    dates.add(endDateTime.toDateStr() + ",上午");
                }
            } else {
                dates.add(lastTemp.toDateStr() + ",全天");
                result += 1;
            }
            condition = nextDay(lastTemp, endDateTime);
        } while (condition);
        response.put("days", result);
        response.put("dates", dates);
        return RespBody.data(response);
    }

    /**
     *
     * 计算出差时长
     * @param startTimeStr
     * @param endTimeStr
     * @return
     */
    @ApiOperation("计算出差时长")
    @GetMapping("/calculateBusinessTripTime")
    public RespBody<HashMap<String, Object>> calculateBusinessTripTime(String startTimeStr, String endTimeStr) {
        final HashMap<String, Object> response = new HashMap<>();
        if (startTimeStr == null || "".equals(startTimeStr) || "请选择".equals(startTimeStr)) {
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        if (endTimeStr == null || "".equals(endTimeStr) || "请选择".equals(endTimeStr)) {
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        final String[] startTime = startTimeStr.split(" ");
        final String[] endTime = endTimeStr.split(" ");
        final DateTime startDateTime = DateUtil.parse(startTime[0], "yyyy年MM月dd日");
        final DateTime endDateTime = DateUtil.parse(endTime[0], "yyyy年MM月dd日");
        if (startDateTime.getTime() > endDateTime.getTime()) {
            throw new BizException("开始时间不能大于结束时间");
        }
        ArrayList<String> dates = new ArrayList<>();
        if (startDateTime.toDateStr().equals(endDateTime.toDateStr())) {
            if (startTime[1].equals(endTime[1])) {
                dates.add(startDateTime.toDateStr() + "," + startTime[1]);
                response.put("days", "0.5");
                response.put("dates", dates);
                return RespBody.data(response);
            }
            dates.add(startDateTime.toDateStr() + ",全天");
            response.put("days", "1.0");
            response.put("dates", dates);
            return RespBody.data(response);
        }
        DateTime lastTemp = DateUtil.parse(startDateTime.toDateStr());
        double result = 0.0;
        boolean condition = false;
        do {
            if (lastTemp.toDateStr().equals(startDateTime.toDateStr())) {
                if ("上午".equals(startTime[1])) {
                    result += 1;
                    dates.add(startDateTime.toDateStr() + ",全天");
                }
                if ("下午".equals(startTime[1])) {
                    result += 0.5;
                    dates.add(startDateTime.toDateStr() + ",下午");
                }
            } else if (lastTemp.toDateStr().equals(endDateTime.toDateStr())) {
                if ("上午".equals(endTime[1])) {
                    result += 0.5;
                    dates.add(endDateTime.toDateStr() + ",上午");
                }
                if ("下午".equals(endTime[1])) {
                    result += 1;
                    dates.add(endDateTime.toDateStr() + ",上午");
                }
            } else {
                dates.add(lastTemp.toDateStr() + ",全天");
                result += 1;
            }
            lastTemp = lastTemp.offset(DateField.DAY_OF_YEAR, 1);
            if (lastTemp.getField(DateField.YEAR) == endDateTime.getField(DateField.YEAR)) {
                //如果为同年 condition需要为 当前日小于等于结束日
                condition = lastTemp.getField(DateField.DAY_OF_YEAR) <= endDateTime.getField(DateField.DAY_OF_YEAR);
            } else {
                //如果不同年 condition需要 为 当前年小于等于结束年
                condition = lastTemp.getField(DateField.YEAR) <= endDateTime.getField(DateField.YEAR);
            }
        } while (condition);
        response.put("days", result);
        response.put("dates", dates);
        return RespBody.data(response);
    }

}
